package com.se.service;

import cn.hutool.core.lang.Pair;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.se.dao.mysql.*;
import com.se.domain.mysql.ActivityDO;
import com.se.domain.mysql.ApplyDO;
import com.se.domain.request.param.ApplyActParam;
import com.se.domain.request.param.ApplyQParam;
import com.se.domain.request.param.QParam;
import com.se.domain.vo.*;
import com.se.enums.ResultCode;
import com.se.exception.ResultException;
import com.se.util.MyDateUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.text.ParseException;
import java.util.*;

@Service
public class ActApplyService {
    @Autowired
    UserDao userDao;
    @Autowired
    ActDao actDao;
    @Autowired
    CatDao catDao;
    @Autowired
    QuestionDao questionDao;
    @Autowired
    ApplyDao applyDao;
    @Autowired
    ActTranService actTranService;
    @Autowired
    ImgDao imgDao;

    private Pair<ActivityDO, ActInfoVO> getActInfoVO(Long actId, Long userId) throws ResultException {
        ActivityDO activityDO = actDao.getByActId(actId);
        if(activityDO == null){
            throw new ResultException(ResultCode.NO_OBJECT);
        }

        //活动未发布且非创建者
        if(!activityDO.getPublish()){
            if(!Objects.equals(activityDO.getUserId(), userId)){
                throw new ResultException(ResultCode.ACT_NO_PUBLISH);
            }
        }
        ActInfoVO vo = new ActInfoVO(new ActVO(activityDO));

        //装填cat信息
        List<Long> catIds = Arrays.stream(activityDO.getCatIds().split(",")).map(Long::parseLong).toList();
        Map<Long, CatVO> catVOMap = catDao.mapVOByCatIds(catIds);
        for (Long catId : catIds) {
            CatVO catVO = catVOMap.get(catId);
            if(catVO != null){
                vo.getAct().getCats().add(catVO);
            }
        }
        //装填user信息
        UserVO userVO = userDao.getVOByUserId(activityDO.getUserId());
        userVO.checkSelf(userId);
        vo.setUser(userVO);

        //装填图片信息
        List<Long> imgIds = activityDO.getImgIdList();
        Map<Long, ImgVO> imgVOMap = imgDao.mapVOByImgIdList(imgIds);
        for (Long imgId : imgIds) {
            ImgVO imgVO = imgVOMap.get(imgId);
            if(imgVO != null){
                vo.getAct().getImgs().add(imgVO);
            }
        }

        return Pair.of(activityDO, vo);
    }
    public ActInfoVO getActSimpleInfo(Long actId, Long userId) throws ResultException {
        Pair<ActivityDO, ActInfoVO> pair = this.getActInfoVO(actId, userId);
        return pair.getValue();
    }

    public ActInfoVO getActFullInfo(Long actId, Long userId) throws ResultException {

        Pair<ActivityDO, ActInfoVO> pair = this.getActInfoVO(actId, userId);
        ActivityDO activityDO = pair.getKey();
        ActInfoVO vo = pair.getValue();

        //装填问卷信息,发起者或报名人
//        Long applyId = applyDao.getApplyIdByQnIdAndUserId(activityDO.getQnId(), userId);
        ApplyDO applyDO = applyDao.getByQnIdAndUserId(activityDO.getQnId(), userId);
        if (vo.getUser().getSelf() || applyDO != null){
            //获取问卷信息
            if(activityDO.getQnId() == null){
                //未发布的问卷
                List<QParam> qParamList = JSONUtil.toList(activityDO.getQnJson(), QParam.class);
                for (QParam qParam : qParamList) {
                    vo.getQn().add(new QVO(qParam));
                }
            }else {
                //已发布问卷
                List<QVO> qvoList = questionDao.listQVOByQnId(activityDO.getQnId());
                vo.setQn(qvoList);
            }
        }

        //装填报名人答案
        if(applyDO != null){
            Map<Long, String> ansMap = applyDao.mapQRecordAnsByApplyId(applyDO.getApplyId());
            for (QVO qvo : vo.getQn()) {
                String ans = ansMap.get(qvo.getQId());
                qvo.setAns(ans);
            }

            vo.setApply(new ApplyVO(applyDO));
        }

        return vo;
    }

    public List<QVO> getQn(Long actId, Long userId) throws ResultException, ParseException {

        ActivityDO activityDO = actDao.getByActId(actId);
        if(activityDO == null){
            throw new ResultException(ResultCode.NO_OBJECT);
        }

        List<QVO> qvoList = questionDao.listQVOByQnId(activityDO.getQnId());

        //之前是否报过名
        Long applyId = applyDao.getApplyIdByQnIdAndUserId(activityDO.getQnId(), userId);
        if(applyId != null){
            //装填报名人答案
            Map<Long, String> ansMap = applyDao.mapQRecordAnsByApplyId(applyId);
            for (QVO qvo : qvoList) {
                String ans = ansMap.get(qvo.getQId());
                qvo.setAns(ans);
            }
        }

        return qvoList;
    }

    private ActivityDO checkApply(Long actId, Long userId) throws ResultException, ParseException {
        ActivityDO activityDO = actDao.getByActId(actId);
        if(activityDO == null){
            throw new ResultException(ResultCode.NO_OBJECT);
        }

        if(!activityDO.getPublish()){
            throw new ResultException(ResultCode.NO_PUBLISH);
        }

        if(Objects.equals(activityDO.getUserId(), userId)){
            throw new ResultException(ResultCode.SELF_NO_APPLY);
        }

        if(activityDO.getSize() != -1 && activityDO.getSize() <= activityDO.getApplyNum()){
            throw new ResultException(ResultCode.SIZE_FULL);
        }

        //检查报名时间
        String applyTimeStr = null, applyEndTimeStr = null;
        if(!StrUtil.isBlank(activityDO.getApplyTime())){
            applyTimeStr = activityDO.getApplyTime();
        }
        if(!StrUtil.isBlank(activityDO.getApplyEndTime())){
            applyEndTimeStr = activityDO.getApplyEndTime();
        }else {
            applyEndTimeStr = activityDO.getStartTime();
        }
        if(!MyDateUtil.currentTimeBetween(applyTimeStr, applyEndTimeStr)){
            throw new ResultException(ResultCode.OUT_APPLY_TIME);
        }
        if (applyDao.existByQnIdAndUserId(activityDO.getQnId(), userId)) {
            throw new ResultException(ResultCode.REPEAT_APPLY);
        }

        return activityDO;
    }

    public Long apply(ApplyActParam applyActParam, Long userId) throws ResultException, ParseException {
        ActivityDO activityDO = this.checkApply(applyActParam.getActId(), userId);


        //检查问卷题目选项内容
        List<QVO> qvoList = questionDao.listQVOByQnId(activityDO.getQnId());
        for (ApplyQParam applyQParam : applyActParam.getQn()) {
            boolean flag = false;
            for (QVO qvo : qvoList) {
                if(Objects.equals(applyQParam.getQId(), qvo.getQId())){
                    qvo.checkAns(applyQParam.getAns());

                    flag = true;
                    break;
                }
            }

            if(!flag){
                throw new ResultException(ResultCode.QN_INVALID.getCode(), "有必选题题目没有填写");
            }
        }


        ApplyDO applyDO = actTranService.applyAct(userId, activityDO, applyActParam);

        return applyDO.getApplyId();
    }

    public void cancelApplyAct(Long applyId, Long userId) throws ResultException, ParseException {
        ApplyDO applyDO = applyDao.getByApplyId(applyId);
        if(applyDO == null){
            throw new ResultException(ResultCode.NO_OBJECT);
        }
        if(!Objects.equals(applyDO.getUserId(), userId)){
            throw new ResultException(ResultCode.NO_PERM);
        }

        ActivityDO activityDO = actDao.getByActId(applyDO.getActId());

        String timeStr = StrUtil.isBlank(activityDO.getApplyEndTime())?
                activityDO.getStartTime() : activityDO.getApplyEndTime();
        if(MyDateUtil.beforeCurrentTime(timeStr)){
            throw new ResultException(ResultCode.CANCEL_TIME_INVALID);
        }

        actTranService.cancelApplyAct(applyId, activityDO.getActId());
    }

    public void sign(Long actId, Long userId) throws ResultException {
        ActivityDO activityDO = actDao.getByActId(actId);
        if(activityDO == null){
            throw new ResultException(ResultCode.NO_OBJECT);
        }
        if(!activityDO.getPublish()){
            throw new ResultException(ResultCode.SIGN_NO_PUBLISH);
        }
        Long applyId = applyDao.getApplyIdByQnIdAndUserId(activityDO.getQnId(), userId);
        if(applyId == null){
            throw new ResultException(ResultCode.SIGN_NO_APPLY);
        }

        applyDao.signByApplyId(applyId);
    }


}
